//
// Created by linfe on 2023/6/5.
//

#ifndef LIVEGRAPH_RINGBUFFER_H
#define LIVEGRAPH_RINGBUFFER_H

#include <cstdio>
#include "stdint.h"

template<typename T>
class RingBuffer {
public:
    explicit RingBuffer(int capacity);
    ~RingBuffer();
    void EnQueue(const T &item);
    T DeQueue();
    const size_t Capacity() const;
    const size_t Size() const;
    bool Full() const;
    bool Empty() const;
    T &Front();
    T &Back();
    T &operator[](int index);
    T &operator[](int index) const;

public:
    T *_data;
    size_t _capacity;
    uint32_t _header;
    uint32_t _tail;
};

template<typename T>
const size_t RingBuffer<T>::Size() const {
    return   (_tail  + _capacity + 1 - _header) %(_capacity + 1);
}

template<typename T>
T &RingBuffer<T>::Back() {
    return _data[(_tail + _capacity) % (_capacity + 1) ];
}

template<typename T>
T &RingBuffer<T>::Front() {
    return _data[_header];
}

template<typename T>
RingBuffer<T>::RingBuffer(int capacity) {
    _capacity = capacity;
    _data = new T[capacity + 1];
    _header = 0;
    _tail = 0;
}

template<typename T>
RingBuffer<T>::~RingBuffer() {
    delete[] _data;
}

template<typename T>
const size_t RingBuffer<T>::Capacity() const {
    return _capacity;
}

template<typename T>
void RingBuffer<T>::EnQueue(const T &item) {
    if (Full()) {
        /* cover header when buffer is full */
        _header = (_header + 1) % (_capacity + 1) ;
    };
    _data[_tail] = item;
    _tail = (_tail + 1) % (_capacity + 1);
}

template<typename T>
T RingBuffer<T>::DeQueue() {
    if (Empty()) throw ("RingBuffer is empty");
    T rst = _data[_header];
    _header = (_header + 1) % (_capacity + 1);
    return rst;
}


template<typename T>
T &RingBuffer<T>::operator[](int index) {
    return _data[(_header + index)%(_capacity + 1)];
}

template<typename T>
T &RingBuffer<T>::operator[](int index) const {
    return _data[(_header + index)%(_capacity + 1)];
}

template<typename T>
bool RingBuffer<T>::Full() const {
    return _header == (_tail + 1) % (_capacity + 1);
}

template<typename T>
bool RingBuffer<T>::Empty() const {
    return _header == _tail;
}


#endif //LIVEGRAPH_RINGBUFFER_H
